#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cJSON_Utils.h"
#ifdef _WIN32
#pragma warning(disable : 4996)
#endif
int main()
{
	int i;
	/* JSON Pointer tests: */
	cJSON *root;
	const char *json="{"
		"\"foo\": [\"bar\", \"baz\"],"
		"\"\": 0,"
		"\"a/b\": 1,"
		"\"c%d\": 2,"
		"\"e^f\": 3,"
		"\"g|h\": 4,"
		"\"i\\\\j\": 5,"
		"\"k\\\"l\": 6,"
		"\" \": 7,"
		"\"m~n\": 8"
	"}";
   
	const char *tests[12]={"","/foo","/foo/0","/","/a~1b","/c%d","/e^f","/g|h","/i\\j","/k\"l","/ ","/m~0n"};
   
	/* JSON Apply Patch tests: */
	const char *patches[15][3]={
	{"{ \"foo\": \"bar\"}", "[{ \"op\": \"add\", \"path\": \"/baz\", \"value\": \"qux\" }]","{\"baz\": \"qux\",\"foo\": \"bar\"}"},
	{"{ \"foo\": [ \"bar\", \"baz\" ] }", "[{ \"op\": \"add\", \"path\": \"/foo/1\", \"value\": \"qux\" }]","{\"foo\": [ \"bar\", \"qux\", \"baz\" ] }"},
	{"{\"baz\": \"qux\",\"foo\": \"bar\"}"," [{ \"op\": \"remove\", \"path\": \"/baz\" }]","{\"foo\": \"bar\" }"},
	{"{ \"foo\": [ \"bar\", \"qux\", \"baz\" ] }","[{ \"op\": \"remove\", \"path\": \"/foo/1\" }]","{\"foo\": [ \"bar\", \"baz\" ] }"},
	{"{ \"baz\": \"qux\",\"foo\": \"bar\"}","[{ \"op\": \"replace\", \"path\": \"/baz\", \"value\": \"boo\" }]","{\"baz\": \"boo\",\"foo\": \"bar\"}"},
	{"{\"foo\": {\"bar\": \"baz\",\"waldo\": \"fred\"},\"qux\": {\"corge\": \"grault\"}}","[{ \"op\": \"move\", \"from\": \"/foo/waldo\", \"path\": \"/qux/thud\" }]","{\"foo\": {\"bar\": \"baz\"},\"qux\": {\"corge\": \"grault\",\"thud\": \"fred\"}}"},
	{"{ \"foo\": [ \"all\", \"grass\", \"cows\", \"eat\" ] }","[ { \"op\": \"move\", \"from\": \"/foo/1\", \"path\": \"/foo/3\" }]","{ \"foo\": [ \"all\", \"cows\", \"eat\", \"grass\" ] }"},
	{"{\"baz\": \"qux\",\"foo\": [ \"a\", 2, \"c\" ]}","[{ \"op\": \"test\", \"path\": \"/baz\", \"value\": \"qux\" },{ \"op\": \"test\", \"path\": \"/foo/1\", \"value\": 2 }]",""},
	{"{ \"baz\": \"qux\" }","[ { \"op\": \"test\", \"path\": \"/baz\", \"value\": \"bar\" }]",""},
	{"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/child\", \"value\": { \"grandchild\": { } } }]","{\"foo\": \"bar\",\"child\": {\"grandchild\": {}}}"},
	{"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/baz\", \"value\": \"qux\", \"xyz\": 123 }]","{\"foo\": \"bar\",\"baz\": \"qux\"}"},
	{"{ \"foo\": \"bar\" }","[{ \"op\": \"add\", \"path\": \"/baz/bat\", \"value\": \"qux\" }]",""},
	{"{\"/\": 9,\"~1\": 10}","[{\"op\": \"test\", \"path\": \"/~01\", \"value\": 10}]",""},
	{"{\"/\": 9,\"~1\": 10}","[{\"op\": \"test\", \"path\": \"/~01\", \"value\": \"10\"}]",""},
	{"{ \"foo\": [\"bar\"] }","[ { \"op\": \"add\", \"path\": \"/foo/-\", \"value\": [\"abc\", \"def\"] }]","{\"foo\": [\"bar\", [\"abc\", \"def\"]] }"}};

	/* Misc tests */
	int numbers[10]={0,1,2,3,4,5,6,7,8,9};
	const char *random="QWERTYUIOPASDFGHJKLZXCVBNM";
	char buf[2]={0,0},*before,*after;
	cJSON *object,*nums,*num6,*sortme;

	const char * null = NULL;
	cJSON* r0  = cJSON_Parse(null);
	const char * nullString = "";
	cJSON* r1 = cJSON_Parse(nullString);
	const char * errJSONObject = "{";
	cJSON* r2 = cJSON_Parse(errJSONObject);
	const char * errJSONArray= "[";
	cJSON* r21 = cJSON_Parse(errJSONArray);

	const char * nullJSONArray = "[]";
	cJSON* r22 = cJSON_Parse(nullJSONArray);

	const char * ExpJSONObject = "{\"detail\":{\"topic\":{\"in_time\":\"2016-04-08 17:07:09\",\"original_url\":\"\",\"reply_count\":0,\"nickname\":\"geliang\",\"score\":85,\"tab\":\"ask\",\"sectionName\":\"\u57FA\u7840\u5E93\",\"good\":0,\"avatar\":\"http:\\/\\/www.cncrk.com\\/updatefiles\\/201306\\/20130606102823667.jpg\",\"id\":\"2e07b6161d9d46618d4c2530cc474b28\",\"content\":\"###\u670D\u52A1\u52A8\u6001\u6CE8\u518C\u548C\u5206\u6D41\u534F\u8BAE\\r\\n\\r\\n##\u6D41\u7A0B\u56FE\\r\\n![](http:\\/\\/192.168.8.4:8085\\/mddoc\\/static\\/upload\\/RaceBlance.png)\\r\\n**\u5176\u4E2D\u76D1\u63A7\u670D\u52A1\u76EE\u524D\u91C7\u53D6CMS\u914D\u7F6E\u65B9\u5F0F\u4E3ARaceServ\u5206\u914D\u670D\u52A1RaceID \u548C MachineID,**\u4ECE\u800C\u65E0\u9700\u6CE8\u518C\\r\\ncms \u6839\u636E\u4E0D\u540CGameID \u914D\u7F6E\u4E0D\u540Cgateway\u7F51\u5173IP\\r\\n\\r\\nsocket\u8FDE\u63A5,RaceID \u548C MachineID\u7EC4\u5408\u6210\u4E3ARaceServ\u670D\u52A1\u5668\u7684\u6807\u8BC6\u4FE1\u606F,\u4EE5\u4E0B\u7B80\u79F0\u4E3AServerID.\\r\\n\u7F51\u5173\u5C06\u6839\u636E**\u7279\u5B9A\u89C4\u5219**(\u6709\u5E8F\u586B\u5751\u6CD5.\u5751\u5347\u5E8F\u6392\u5217,\u54EA\u5751\u4E0D\u6EE1\u586B\u54EA\u91CC)\u8F6C\u53D1\u5BA2\u6237\u7AEF\u6D88\u606F\u7ED9ServerID\u6240\u5728\u7684\u8FDE\u63A5\\r\\n\u7F51\u5173\u5C06**\u7F13\u5B58\u7528\u6237\u4E0A\u6B21\u767B\u5F55**\u7684ServerID.\\r\\n\\r\\n- \u5C0F\u7AEF\u5E8F\\r\\n- TCP\\r\\n- v1.0\\r\\n----\\r\\n\\r\\n##\u670D\u52A1\u6CE8\u518C\u534F\u8BAE \\r\\nRaceServ->Gateway\\r\\n\u7528\u4E8E\u670D\u52A1\u5668\u5411\u7F51\u5173\u6CE8\u518C \\r\\n\\r\\n| Length | version | seq  | field1| field2 | cmd |\\r\\n| -----  |-----| ----- | -----  | ----- | ----- |\\r\\n| 4byte| 4byte| 4byte  | 4byte|4byte|4byte  |\\r\\n| 24| version| seq  | RaceID| MachineID| 2002  |\\r\\n\\r\\n\u5176\u4E2DRaceID\u4E3A\u8D1F\u6570\u9012\u51CF \\r\\n##\u670D\u52A1\u72B6\u6001\u540C\u6B65\u534F\u8BAE \\r\\nRaceServ->Gateway\\r\\n\u7528\u4E8E\u670D\u52A1\u5668\u5411\u7F51\u5173\u62A5\u544A\u8D1F\u8F7D\u72B6\u6001\\r\\n\\r\\n| Length | version | seq  | field1| field2 | cmd |stats|\\r\\n| -----  |-----| ----- | -----  | ----- | ----- |----- |\\r\\n| 4byte| 4byte| 4byte  | 4byte|4byte|4byte  |1byte |\\r\\n| 24| version| seq  | RaceID| MachineID| 2009  | 0\\/1|\\r\\n\\r\\n0\u4E3A\u53EF\u7528\\r\\n1\u4E3A\u4E0D\u53EF\u7528,\u8BE5\u72B6\u6001\u4E0B\u5C06\u4E0D\u8F6C\u53D1\u6D88\u606F,\u5E76\u544A\u8B66\\r\\n\\r\\n----\\r\\n##\u5BA2\u6237\u7AEF\u767B\u5F55\u7F51\u5173\u534F\u8BAE\\r\\nclient->GateWay\\r\\n\\r\\n\u5BA2\u6237\u7AEF\u4ECE\u76D1\u63A7\u670D\u52A1\u6839\u636EGameID\u83B7\u53D6\u7F51\u5173IP\u548CRaceID\u767B\u5F55\u7F51\u5173\\r\\n\\r\\n| Length | version | seq  | field1| field2 | cmd | userid |token|\\r\\n| -----  |-----| ----- | -----  | ----- | ----- | ----- | ----- |\\r\\n| 4byte| 4byte| 4byte  | 4byte|4byte|4byte  |4byte  |32byte  |\\r\\n| 58| version| seq  | GameID| RaceID| 2501  |xxxx|xxxxxxxx  |\",\"title\":\"\u670D\u52A1\u52A8\u6001\u6CE8\u518C\u548C\u5206\u6D41\u534F\u8BAE\",\"reposted\":0,\"s_id\":1,\"author_id\":\"2\",\"view\":15,\"modify_time\":\"2016-04-08 19:52:01\",\"signature\":\"000\",\"show_status\":1,\"top\":0},\"replies\":[1,2,3]},\"description\":\"success\",\"code\":\"200\"}";
	cJSON* r3 = cJSON_Parse(ExpJSONObject);
	cJSON* codeJSON = cJSON_GetObjectItem(r3, "code");
	printf("code: %s \n", codeJSON->valuestring);
	printf("description: %s\n", cJSON_GetObjectItem(r3, "description")->valuestring);
	cJSON* topicJsonObject = cJSON_GetObjectItem(cJSON_GetObjectItem(r3, "detail"),"topic");

	printf("topic.content :%s\n", cJSON_GetObjectItem(topicJsonObject, "content")->valuestring);
	printf("topic.show_status :%d\n", cJSON_GetObjectItem(topicJsonObject, "show_status")->valueint);
	cJSON_Delete(r3);
	r3 = NULL;

	const char * ExpJSONArray = "[0,1,2,3,4,5,6,7,8,9]";
	cJSON* r4 = cJSON_Parse(ExpJSONArray);
	printf("ExpJSONArray.size :%d\n", cJSON_GetArraySize(r4));
	for(int j = 0; j < cJSON_GetArraySize(r4); j++)
	{
		printf("ExpJSONArray.path :%d\n", cJSON_GetArrayItem(r4, j)->valueint);
	}

	cJSON_Delete(r4);
	r4 = NULL;

	printf("JSON Pointer Tests\n");
	root=cJSON_Parse(json);

	for (i=0;i<12;i++)
	{
		char *output=cJSON_Print(cJSONUtils_GetPointer(root,tests[i]));
		printf("Test %d:\n%s\n\n",i+1,output);
		free(output);
	}
	cJSON_Delete(root);


	printf("JSON Apply Patch Tests\n");
	for (i=0;i<15;i++)
	{
		cJSON *object=cJSON_Parse(patches[i][0]);
		cJSON *patch=cJSON_Parse(patches[i][1]);
		int err=cJSONUtils_ApplyPatches(object,patch);
		char *output=cJSON_Print(object);
		printf("Test %d (err %d):\n%s\n\n",i+1,err,output);
		free(output);cJSON_Delete(object);cJSON_Delete(patch);
	}

	/* JSON Generate Patch tests: */
	printf("JSON Generate Patch Tests\n");
	for (i=0;i<15;i++)
	{
		cJSON *from,*to,*patch;char *out;
		if (!strlen(patches[i][2])) continue;
		from=cJSON_Parse(patches[i][0]);
		to=cJSON_Parse(patches[i][2]);
		patch=cJSONUtils_GeneratePatches(from,to);
		out=cJSON_Print(patch);
		printf("Test %d: (patch: %s):\n%s\n\n",i+1,patches[i][1],out);
		free(out);cJSON_Delete(from);cJSON_Delete(to);cJSON_Delete(patch);
	}

	/* Misc tests: */
	printf("JSON Pointer construct\n");
	object=cJSON_CreateObject();
	nums=cJSON_CreateIntArray(numbers,10);
	num6=cJSON_GetArrayItem(nums,6);
	cJSON_AddItemToObject(object,"numbers",nums);
	char *temp=cJSONUtils_FindPointerFromObjectTo(object,num6);
	printf("Pointer: [%s]\n",temp);
	free(temp);
	temp=cJSONUtils_FindPointerFromObjectTo(object,nums);
	printf("Pointer: [%s]\n",temp);
	free(temp);
	temp=cJSONUtils_FindPointerFromObjectTo(object,object);
	printf("Pointer: [%s]\n",temp);
	free(temp);
	cJSON_Delete(object);

	/* JSON Sort test: */
	sortme=cJSON_CreateObject();
	for (i=0;i<26;i++)
	{
		buf[0]=random[i];cJSON_AddItemToObject(sortme,buf,cJSON_CreateNumber(1));
	}
	before=cJSON_PrintUnformatted(sortme);
	cJSONUtils_SortObject(sortme);
	after=cJSON_PrintUnformatted(sortme);
	printf("Before: [%s]\nAfter: [%s]\n\n",before,after);
	free(before);free(after);cJSON_Delete(sortme);		
#ifdef _WIN32
	system("pause");
#endif
}
